<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>流程图设计</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            display: flex;
            flex-direction: column;
            height: 100vh;
            background-color: #f5f7fa;
        }

        #toolbar {
            position: fixed;
            top: 50%;
            right: 20px;
            transform: translateY(-50%);
            display: flex;
            flex-direction: column;
            gap: 10px;
            background-color: white;
            padding: 10px;
            border-radius: 10px;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
        }

        button {
            padding: 8px 12px;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 14px;
            transition: background-color 0.3s ease;
        }

        button:hover {
            background: linear-gradient(135deg, #5a6dc9 0%, #683d8e 100%);
        }

        button.active {
            background: linear-gradient(135deg, #f44336 0%, #c62828 100%);
        }

        #canvas-container {
            flex: 1;
            overflow: auto;
            position: relative;
            background-color: white;
            background-image: linear-gradient(#eee 1px, transparent 1px),
                linear-gradient(90deg, #eee 1px, transparent 1px);
            background-size: 20px 20px;
        }

        #flowchart-canvas {
            width: 100%;
            height: 80%;
        }

        .node {
            position: absolute;
            width: 120px;
            min-height: 60px;
            background-color: white;
            border: 2px solid #667eea;
            border-radius: 6px;
            display: flex;
            align-items: center;
            justify-content: center;
            cursor: move;
            user-select: none;
            box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
            padding: 10px;
            text-align: center;
            word-break: break-word;
            transition: box-shadow 0.3s ease, border-color 0.3s ease;
        }

        .node:hover {
            box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
            border-color: #45a049;
        }

        .node.selected {
            border-color: #f44336;
            box-shadow: 0 0 0 2px rgba(244, 67, 54, 0.3);
        }

        .node.diamond {
            width: 100px;
            height: 100px;
            transform: rotate(45deg);
        }

        .node.diamond .node-content {
            transform: rotate(-45deg);
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
        }

        .node.ellipse {
            border-radius: 50%;
            width: 100px;
            height: 60px;
        }

        .connector {
            width: 12px;
            height: 12px;
            background-color: transparent;
            border-radius: 50%;
            position: absolute;
            cursor: pointer;
            border: transparent;
            z-index: 10;
            transition: background-color 0.3s ease, transform 0.3s ease;
        }

        .connector:hover {
            background-color: #f44336;
            transform: scale(1.2);
        }

        .connector.top {
            top: -6px;
            left: 50%;
            transform: translateX(-50%);
        }

        .connector.bottom {
            bottom: -6px;
            left: 50%;
            transform: translateX(-50%);
        }

        .connector.left {
            left: -6px;
            top: 50%;
            transform: translateY(-50%);
        }

        .connector.right {
            right: -6px;
            top: 50%;
            transform: translateY(-50%);
        }

        #status-bar {
            background-color: white;
            padding: 5px 10px;
            border-top: 1px solid #ddd;
            font-size: 12px;
            color: #666;
        }

        path {
            stroke: #667eea;
            stroke-width: 2;
            fill: none;
            stroke-linecap: round;
            stroke-linejoin: round;
            transition: stroke 0.3s ease;
        }

        path:hover {
            stroke: #45a049;
        }

        path.selected {
            stroke: #f44336;
        }
    </style>
</head>

<body>
    <div id="canvas-container">
        <svg id="flowchart-canvas"></svg>
    </div>

    <div id="toolbar">
        <button id="add-rectangle">添加矩形</button>
        <button id="add-diamond">添加菱形</button>
        <button id="add-ellipse">添加椭圆</button>
        <button id="connect-btn">连接模式</button>
        <button id="delete-node-btn">删除节点</button>
        <button id="delete-line-btn">删除连线</button>
        <button id="save-btn">保存流程</button>
        <button id="load-btn">加载流程</button>
    </div>

    <div id="status-bar">就绪 - 点击"添加矩形"按钮开始绘制流程图</div>

    <script>
        document.addEventListener('DOMContentLoaded', function () {
            const canvas = document.getElementById('flowchart-canvas');
            const canvasContainer = document.getElementById('canvas-container');
            const statusBar = document.getElementById('status-bar');

            let selectedNode = null;
            let selectedLine = null;
            let isConnectMode = false;
            let startConnector = null;
            let nodes = [];
            let connections = [];
            let nextNodeId = 1;

            // 初始化事件监听
            document.getElementById('add-rectangle').addEventListener('click', () => addNode('rectangle', '步骤 ' + nextNodeId));
            document.getElementById('add-diamond').addEventListener('click', () => addNode('diamond', '决策 ' + nextNodeId));
            document.getElementById('add-ellipse').addEventListener('click', () => addNode('ellipse', '开始/结束 ' + nextNodeId));
            document.getElementById('connect-btn').addEventListener('click', toggleConnectMode);
            document.getElementById('delete-node-btn').addEventListener('click', deleteSelectedNode);
            document.getElementById('delete-line-btn').addEventListener('click', deleteSelectedLine);
            document.getElementById('save-btn').addEventListener('click', saveFlowchart);
            document.getElementById('load-btn').addEventListener('click', loadFlowchart);

            // 添加新节点
            function addNode(type, text) {
                const nodeId = 'node-' + nextNodeId++;
                const node = document.createElement('div');
                node.className = 'node';
                node.id = nodeId;
                node.dataset.type = type;

                // 设置节点内容
                const nodeContent = document.createElement('div');
                nodeContent.className = 'node-content';
                nodeContent.textContent = text;
                node.appendChild(nodeContent);

                // 设置初始位置为画布中央
                const containerRect = canvasContainer.getBoundingClientRect();
                const scrollLeft = canvasContainer.scrollLeft;
                const scrollTop = canvasContainer.scrollTop;

                node.style.left = (containerRect.width / 2 - 60 + scrollLeft) + 'px';
                node.style.top = (containerRect.height / 2 - 30 + scrollTop) + 'px';

                // 根据类型设置特殊样式
                if (type === 'diamond') {
                    node.classList.add('diamond');
                } else if (type === 'ellipse') {
                    node.classList.add('ellipse');
                }

                // 添加连接点
                addConnectors(node);

                // 添加到画布
                canvasContainer.appendChild(node);

                // 使节点可拖动
                makeDraggable(node);

                // 添加到节点数组
                nodes.push({
                    id: nodeId,
                    type: type,
                    text: text,
                    x: parseInt(node.style.left),
                    y: parseInt(node.style.top)
                });

                // 选中新节点
                selectNode(node);

                updateStatus('已添加新节点: ' + text);
            }

            // 添加连接点
            function addConnectors(node) {
                const positions = ['top', 'right', 'bottom', 'left'];

                positions.forEach(pos => {
                    const connector = document.createElement('div');
                    connector.className = `connector ${pos}`;
                    connector.dataset.position = pos;
                    connector.dataset.nodeId = node.id;

                    connector.addEventListener('mousedown', function (e) {
                        if (isConnectMode) {
                            e.stopPropagation();
                            startConnector = {
                                nodeId: node.id,
                                position: pos
                            };
                        }
                    });

                    connector.addEventListener('mouseup', function (e) {
                        if (isConnectMode && startConnector) {
                            e.stopPropagation();
                            const endConnector = {
                                nodeId: node.id,
                                position: pos
                            };

                            if (startConnector.nodeId !== endConnector.nodeId) {
                                createConnection(startConnector, endConnector);
                            }

                            startConnector = null;
                        }
                    });

                    node.appendChild(connector);
                });
            }

            // 创建连接线
            function createConnection(startConnector, endConnector) {
                const startNode = document.getElementById(startConnector.nodeId);
                const endNode = document.getElementById(endConnector.nodeId);

                if (!startNode || !endNode) return;

                // 计算连接点坐标
                const startPoint = getConnectorPosition(startNode, startConnector.position);
                const endPoint = getConnectorPosition(endNode, endConnector.position);

                // 创建SVG路径
                const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
                const pathId = `connection-${connections.length}`;
                path.id = pathId;
                path.setAttribute('stroke', '#667eea');
                path.setAttribute('stroke-width', '2');
                path.setAttribute('fill', 'none');
                path.setAttribute('marker-end', 'url(#arrowhead)');

                // 计算路径数据
                const pathData = calculatePathData(startPoint, endPoint);
                path.setAttribute('d', pathData);

                // 添加到SVG画布
                canvas.appendChild(path);

                // 添加到连接数组
                connections.push({
                    id: pathId,
                    start: startConnector,
                    end: endConnector,
                    path: pathData,
                    element: path
                });

                // 更新箭头标记
                updateArrowMarker();

                // 添加点击事件监听器
                path.addEventListener('click', function () {
                    selectLine(path);
                });

                updateStatus(`已创建连接: ${startNode.textContent} → ${endNode.textContent}`);
            }

            // 获取连接点位置
            function getConnectorPosition(node, position) {
                const rect = node.getBoundingClientRect();
                const containerRect = canvasContainer.getBoundingClientRect();
                const scrollLeft = canvasContainer.scrollLeft;
                const scrollTop = canvasContainer.scrollTop;

                let x, y;

                switch (position) {
                    case 'top':
                        x = rect.left + rect.width / 2 - containerRect.left + scrollLeft;
                        y = rect.top - containerRect.top + scrollTop;
                        break;
                    case 'right':
                        x = rect.left + rect.width - containerRect.left + scrollLeft;
                        y = rect.top + rect.height / 2 - containerRect.top + scrollTop;
                        break;
                    case 'bottom':
                        x = rect.left + rect.width / 2 - containerRect.left + scrollLeft;
                        y = rect.top + rect.height - containerRect.top + scrollTop;
                        break;
                    case 'left':
                        x = rect.left - containerRect.left + scrollLeft;
                        y = rect.top + rect.height / 2 - containerRect.top + scrollTop;
                        break;
                }

                return { x, y };
            }

            // 计算路径数据
            function calculatePathData(startPoint, endPoint) {
                const dx = endPoint.x - startPoint.x;
                const dy = endPoint.y - startPoint.y;

                // 计算控制点
                const controlPoint1 = {
                    x: startPoint.x + dx * 0.5,
                    y: startPoint.y
                };

                const controlPoint2 = {
                    x: endPoint.x - dx * 0.5,
                    y: endPoint.y
                };

                return `M ${startPoint.x} ${startPoint.y} 
                        C ${controlPoint1.x} ${controlPoint1.y}, 
                          ${controlPoint2.x} ${controlPoint2.y}, 
                          ${endPoint.x} ${endPoint.y}`;
            }

            // 更新箭头标记
            function updateArrowMarker() {
                let marker = document.getElementById('arrowhead');

                if (!marker) {
                    const defs = document.createElementNS('http://www.w3.org/2000/svg', 'defs');
                    marker = document.createElementNS('http://www.w3.org/2000/svg', 'marker');
                    marker.id = 'arrowhead';
                    marker.setAttribute('markerWidth', '10');
                    marker.setAttribute('markerHeight', '7');
                    marker.setAttribute('refX', '9');
                    marker.setAttribute('refY', '3.5');
                    marker.setAttribute('orient', 'auto');

                    const arrow = document.createElementNS('http://www.w3.org/2000/svg', 'polygon');
                    arrow.setAttribute('points', '0 0, 10 3.5, 0 7');
                    arrow.setAttribute('fill', '#667eea');

                    marker.appendChild(arrow);
                    defs.appendChild(marker);
                    canvas.insertBefore(defs, canvas.firstChild);
                }
            }

            // 使节点可拖动
            function makeDraggable(node) {
                let isDragging = false;
                let startX, startY, startLeft, startTop;

                node.addEventListener('mousedown', function (e) {
                    if (e.target.classList.contains('connector')) return;

                    isDragging = true;
                    startX = e.clientX;
                    startY = e.clientY;
                    startLeft = parseInt(node.style.left);
                    startTop = parseInt(node.style.top);

                    // 选中节点
                    selectNode(node);

                    e.preventDefault();
                });

                document.addEventListener('mousemove', function (e) {
                    if (!isDragging) return;

                    const dx = e.clientX - startX;
                    const dy = e.clientY - startY;

                    const newLeft = startLeft + dx;
                    const newTop = startTop + dy;

                    // 更新位置
                    node.style.left = newLeft + 'px';
                    node.style.top = newTop + 'px';

                    // 更新节点数据
                    const nodeIndex = nodes.findIndex(n => n.id === node.id);
                    if (nodeIndex !== -1) {
                        nodes[nodeIndex].x = newLeft;
                        nodes[nodeIndex].y = newTop;
                    }

                    // 更新连接线
                    updateConnections(node.id);
                });

                document.addEventListener('mouseup', function () {
                    isDragging = false;
                });

                // 双击编辑文本
                node.querySelector('.node-content').addEventListener('dblclick', function () {
                    const content = this.textContent;
                    const input = document.createElement('input');
                    input.type = 'text';
                    input.value = content;
                    input.style.cssText = `
                        width: 100%;
                        padding: 5px;
                        border: 1px solid #ccc;
                        border-radius: 3px;
                        text-align: center;
                    `;

                    this.innerHTML = '';
                    this.appendChild(input);
                    input.focus();

                    input.addEventListener('blur', function () {
                        const newText = this.value;
                        this.parentNode.textContent = newText;

                        // 更新节点数据
                        const nodeIndex = nodes.findIndex(n => n.id === node.id);
                        if (nodeIndex !== -1) {
                            nodes[nodeIndex].text = newText;
                        }

                        updateStatus('已更新文本: ' + newText);
                    });

                    input.addEventListener('keypress', function (e) {
                        if (e.key === 'Enter') {
                            this.blur();
                        }
                    });
                });
            }

            // 更新与节点相关的连接线
            function updateConnections(nodeId) {
                connections.forEach(conn => {
                    if (conn.start.nodeId === nodeId || conn.end.nodeId === nodeId) {
                        const startNode = document.getElementById(conn.start.nodeId);
                        const endNode = document.getElementById(conn.end.nodeId);

                        if (startNode && endNode) {
                            const startPoint = getConnectorPosition(startNode, conn.start.position);
                            const endPoint = getConnectorPosition(endNode, conn.end.position);

                            const pathData = calculatePathData(startPoint, endPoint);
                            conn.element.setAttribute('d', pathData);
                            conn.path = pathData;
                        }
                    }
                });
            }

            // 选择节点
            function selectNode(node) {
                // 取消之前选中的节点
                if (selectedNode) {
                    selectedNode.classList.remove('selected');
                }

                // 取消之前选中的连线
                if (selectedLine) {
                    selectedLine.classList.remove('selected');
                    selectedLine = null;
                }

                // 选中新节点
                selectedNode = node;
                if (node) {
                    node.classList.add('selected');
                }
            }

            // 选择连线
            function selectLine(line) {
                // 取消之前选中的节点
                if (selectedNode) {
                    selectedNode.classList.remove('selected');
                    selectedNode = null;
                }

                // 取消之前选中的连线
                if (selectedLine) {
                    selectedLine.classList.remove('selected');
                }

                // 选中新连线
                selectedLine = line;
                if (line) {
                    line.classList.add('selected');
                }
            }

            // 删除选中节点
            function deleteSelectedNode() {
                if (selectedNode) {
                    const nodeId = selectedNode.id;

                    // 删除相关连接线
                    connections = connections.filter(conn => {
                        if (conn.start.nodeId === nodeId || conn.end.nodeId === nodeId) {
                            conn.element.remove();
                            return false;
                        }
                        return true;
                    });

                    // 从节点数组中移除
                    nodes = nodes.filter(n => n.id !== nodeId);

                    // 从DOM中移除
                    selectedNode.remove();

                    // 清除选中状态
                    selectNode(null);

                    updateStatus('已删除节点');
                }
            }

            // 删除选中连线
            function deleteSelectedLine() {
                if (selectedLine) {
                    const lineId = selectedLine.id;

                    // 从连接数组中移除
                    connections = connections.filter(conn => {
                        if (conn.id === lineId) {
                            conn.element.remove();
                            return false;
                        }
                        return true;
                    });

                    // 清除选中状态
                    selectedLine.classList.remove('selected');
                    selectedLine = null;

                    updateStatus('已删除连线');
                }
            }

            // 切换连接模式
            function toggleConnectMode() {
                isConnectMode = !isConnectMode;
                const btn = document.getElementById('connect-btn');
                btn.classList.toggle('active', isConnectMode);

                if (isConnectMode) {
                    updateStatus('连接模式: 点击一个连接点并拖动到另一个连接点');
                } else {
                    updateStatus('选择模式');
                    startConnector = null;
                }
            }

            // 保存流程图
            function saveFlowchart() {
                const data = {
                    nodes: nodes,
                    connections: connections,
                    nextNodeId: nextNodeId,
                    savedAt: new Date().toISOString()
                };

                const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
                const url = URL.createObjectURL(blob);
                const a = document.createElement('a');
                a.href = url;
                a.download = '流程图-' + new Date().toISOString().slice(0, 10) + '.json';
                a.click();
                URL.revokeObjectURL(url);

                updateStatus('流程图已保存');
            }

            // 加载流程图
            function loadFlowchart() {
                const input = document.createElement('input');
                input.type = 'file';
                input.accept = '.json';

                input.onchange = e => {
                    const file = e.target.files[0];
                    if (!file) return;

                    const reader = new FileReader();

                    reader.onload = event => {
                        try {
                            const data = JSON.parse(event.target.result);
                            clearCanvas();
                            loadFlowchartData(data);
                            updateStatus('流程图已加载: ' + file.name);
                        } catch (error) {
                            alert('加载文件失败: ' + error.message);
                            updateStatus('加载失败: ' + error.message);
                        }
                    };

                    reader.readAsText(file);
                };

                input.click();
            }

            // 清空画布
            function clearCanvas() {
                // 删除所有节点
                document.querySelectorAll('.node').forEach(node => {
                    node.remove();
                });

                // 删除所有连接线
                while (canvas.firstChild) {
                    canvas.removeChild(canvas.firstChild);
                }

                // 清空数据
                nodes = [];
                connections = [];
                selectedNode = null;
                selectedLine = null;
                nextNodeId = 1;
            }

            // 加载流程图数据
            function loadFlowchartData(data) {
                if (!data.nodes || !data.connections) return;

                // 创建节点
                data.nodes.forEach(nodeData => {
                    const node = document.createElement('div');
                    node.className = 'node';
                    node.id = nodeData.id;
                    node.dataset.type = nodeData.type;

                    // 设置节点内容
                    const nodeContent = document.createElement('div');
                    nodeContent.className = 'node-content';
                    nodeContent.textContent = nodeData.text;
                    node.appendChild(nodeContent);

                    // 设置位置
                    node.style.left = nodeData.x + 'px';
                    node.style.top = nodeData.y + 'px';

                    // 根据类型设置特殊样式
                    if (nodeData.type === 'diamond') {
                        node.classList.add('diamond');
                    } else if (nodeData.type === 'ellipse') {
                        node.classList.add('ellipse');
                    }

                    // 添加连接点
                    addConnectors(node);

                    // 添加到画布
                    canvasContainer.appendChild(node);

                    // 使节点可拖动
                    makeDraggable(node);

                    // 更新nextNodeId
                    const idNum = parseInt(nodeData.id.split('-')[1]);
                    if (idNum >= nextNodeId) {
                        nextNodeId = idNum + 1;
                    }
                });

                // 创建连接线
                data.connections.forEach(connData => {
                    const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
                    path.id = connData.id;
                    path.setAttribute('stroke', '#667eea');
                    path.setAttribute('stroke-width', '2');
                    path.setAttribute('fill', 'none');
                    path.setAttribute('marker-end', 'url(#arrowhead)');
                    path.setAttribute('d', connData.path);

                    canvas.appendChild(path);

                    // 添加到连接数组
                    connections.push({
                        id: connData.id,
                        start: connData.start,
                        end: connData.end,
                        path: connData.path,
                        element: path
                    });

                    // 添加点击事件监听器
                    path.addEventListener('click', function () {
                        selectLine(path);
                    });
                });

                // 更新箭头标记
                updateArrowMarker();
            }

            // 更新状态栏
            function updateStatus(message) {
                statusBar.textContent = message;
            }

            // 键盘快捷键
            document.addEventListener('keydown', function (e) {
                // 删除键
                if (e.key === 'Delete') {
                    if (selectedNode) {
                        deleteSelectedNode();
                    } else if (selectedLine) {
                        deleteSelectedLine();
                    }
                }
            });

        });
    </script>
</body>

</html>    